﻿using System;
using System.IO;
using UnityEngine;
using UnityEditor;

namespace JinndevEditor {

    public class GenerateMaskEditor : EditorWindow {

        [MenuItem(CommonEditorConst.EditorMenu + "/MaskMap生成器")]
        public static void Open() {
            var window = GetWindow<GenerateMaskEditor>("MaskMap生成器");
            window.Show();
        }

        private const int Metallic = 0;
        private const int Occlusion = 1;
        private const int DetailMask = 2;
        private const int Smoothness = 3; // Glossiness
        private const int Roughness = 4;

        private const int textureLength = 200;

        private Texture2D[] inputTextures = new Texture2D[5];
        private string[] inputNames = new string[] { "(R)Metallic", "(G)Occlusion", "(B)DetailMask", "(A)Smoothness/Glossiness", "(A)Roughness" };
        private string[] inputSuffix = new string[] { "Metallic", "Occlusion,AO", "Detail,DetailMask", "Smoothness,Glossiness", "Roughness" };
        private ColorChannel[] inputChannels = new ColorChannel[] { ColorChannel.G, ColorChannel.G, ColorChannel.G, ColorChannel.G, ColorChannel.G };

        private string[] outputTypes = new string[] { "PNG", "TGA"};
        private string outputType = "PNG";

        protected void OnGUI() {
            EditorGUILayout.Space(10);

            // 输入贴图
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.Space(10);
            bool hasInput = false;
            for (int i = 0; i < 5; i++) {
                DrawInputTextures(i);
                if (i == Smoothness) {
                    EditorGUILayout.LabelField("or", GUILayout.Width(15), GUILayout.Height(textureLength));
                }
                else {
                    EditorGUILayout.Space(40);
                }
                if(inputTextures[i] != null) {
                    hasInput = true;
                }
            }
            GUILayout.FlexibleSpace();
            EditorGUILayout.Space(10);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(40);

            EditorGUILayout.BeginHorizontal();
            GUI.enabled = hasInput;
            if (GUILayout.Button("自动设置其他", GUILayout.Width(100), GUILayout.Height(40))) {
                AutoSetOtherInput();
            }
            if (GUILayout.Button("全部清除", GUILayout.Width(100), GUILayout.Height(40))) {
                ClearAllInput();
            }
            GUI.enabled = true;
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space(40);

            // 生成
            EditorGUILayout.BeginHorizontal();
            foreach (string type in outputTypes) {
                EditorGUILayout.LabelField(type, GUILayout.Width(30));
                if (EditorGUILayout.Toggle(outputType == type, GUILayout.Width(20))) {
                    outputType = type;
                }
            }
            EditorGUILayout.EndHorizontal();

            if (GUILayout.Button("生成", GUILayout.Width(100), GUILayout.Height(40))) {
                Generate();
            }

            EditorGUILayout.Space(10);
        }

        private void DrawInputTextures(int index) {
            EditorGUILayout.BeginVertical();

            // 输入纹理
            inputTextures[index] = EditorGUILayout.ObjectField(inputTextures[index], typeof(Texture2D), false, GUILayout.Width(textureLength), GUILayout.Height(textureLength)) as Texture2D;

            // 输入通道
            GUI.enabled = inputTextures[index] != null;
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("In", GUILayout.Width(30));

            foreach (ColorChannel channel in Enum.GetValues(typeof(ColorChannel))) {
                EditorGUILayout.LabelField(channel.ToString(), GUILayout.Width(10));
                if (EditorGUILayout.Toggle(inputChannels[index] == channel, GUILayout.Width(20))) {
                    inputChannels[index] = channel;
                }
            }
            EditorGUILayout.EndHorizontal();

            // 输出通道
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Out", GUILayout.Width(30));
            EditorGUILayout.LabelField(inputNames[index], GUILayout.Width(textureLength - 30));
            EditorGUILayout.EndHorizontal();

            // 删除按钮
            if (GUILayout.Button("清除", GUILayout.Width(80), GUILayout.Height(30))) {
                inputTextures[index] = null;
            }
            GUI.enabled = true;

            EditorGUILayout.EndVertical();
        }

        private void ClearAllInput() {
            for (int i = 0; i < inputTextures.Length; i++) {
                inputTextures[i] = null;
            }
        }

        private void AutoSetOtherInput() {
            Texture2D fromTexture = CommonEditorUtil.GetFirstNonNull(inputTextures);
            if(fromTexture == null) {
                return;
            }

            string prefix = CommonEditorUtil.GetPrefix(fromTexture);
            if (string.IsNullOrWhiteSpace(prefix)) {
                return;
            }

            string assetPath = AssetDatabase.GetAssetPath(fromTexture);
            string dir = Path.GetDirectoryName(assetPath);
            string ext = Path.GetExtension(assetPath);

            string format = Path.Combine(dir, prefix + "_{0}" + ext);

            for (int i = 0; i < inputTextures.Length; i++) {
                Texture2D inputTexture = inputTextures[i];
                if(inputTexture == null) {
                    string[] suffixArray = inputSuffix[i].Split(',');
                    foreach(string suffix in suffixArray) {
                        string path = string.Format(format, suffix);
                        inputTextures[i] = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
                    }
                }
            }
        }

        private void Generate() {
            // 保存位置
            string dir = CommonEditorUtil.GetDir(inputTextures);
            string prefix = CommonEditorUtil.GetPrefix(inputTextures);
            string name = prefix == null ? "Mask" : prefix + "_Mask";
            string saveFile = EditorUtility.SaveFilePanel("选择保存位置", dir, name, outputType.ToLower());
            if (string.IsNullOrWhiteSpace(saveFile)) {
                return;
            }

            // 获取长宽
            int width = 0;
            int height = 0;
            for (int i = 0; i < inputTextures.Length; i++) {
                Texture2D inputTexture = inputTextures[i];
                if (inputTexture != null) {
                    if (width == 0) {
                        width = inputTexture.width;
                        height = inputTexture.height;
                    }
                    else if (width != inputTexture.width) {
                        Debug.LogError("输入纹理的长宽不一致");
                        return;
                    }
                }
            }

            // isReadable = true
            for (int i = 0; i < inputTextures.Length; i++) {
                CommonEditorUtil.SetReadable(inputTextures[i], true);
            }

            // SetPixels
            Texture2D outputTexture = new Texture2D(width, height);
            int step = 0;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    if (step++ % 256 == 0) {
                        EditorUtility.DisplayProgressBar("SetPixels", $"({x}, {y})", (float)(y * width + x) / (width * height));
                    }
                    Color outputColor = new Color(0, 0, 0, 0);
                    CommonEditorUtil.SetPixel(inputTextures[Metallic], x, y, inputChannels[Metallic], ColorChannel.R, false, ref outputColor);
                    CommonEditorUtil.SetPixel(inputTextures[Occlusion], x, y, inputChannels[Occlusion], ColorChannel.G, false, ref outputColor);
                    CommonEditorUtil.SetPixel(inputTextures[DetailMask], x, y, inputChannels[DetailMask], ColorChannel.B, false, ref outputColor);
                    if (!CommonEditorUtil.SetPixel(inputTextures[Smoothness], x, y, inputChannels[Smoothness], ColorChannel.A, false, ref outputColor)) {
                        CommonEditorUtil.SetPixel(inputTextures[Roughness], x, y, inputChannels[Roughness], ColorChannel.A, true, ref outputColor);
                    }
                    outputTexture.SetPixel(x, y, outputColor);
                }
            }

            // isReadable = false
            for (int i = 0; i < inputTextures.Length; i++) {
                CommonEditorUtil.SetReadable(inputTextures[i], false);
            }

            // Save output
            byte[] bytes;
            if (outputType == "TGA") {
                bytes = outputTexture.EncodeToTGA();
            }
            else {
                bytes = outputTexture.EncodeToPNG();
            }
            DestroyImmediate(outputTexture);

            File.WriteAllBytes(saveFile, bytes);
            AssetDatabase.Refresh();
            EditorUtility.ClearProgressBar();
        }

    }
}
